package com.jpsl.core.reflection.property.m;

import com.jpsl.core.reflection.property.MetaClassSupport;
import com.jpsl.core.util.CollectionUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.function.BiConsumer;

/**
 * 通过 {@link Method} 来取值和赋值
 *
 * @author 懒王猫
 */
public class ByMethodMetaClass extends MetaClassSupport {

    public ByMethodMetaClass(Class<?> beanType) {
        super(beanType);
    }

    @Override
    protected void init() {
        for (Method m : beanType.getMethods()) {
            processMethod(m, (prop, getter) -> {
                addProperty(prop);
                addGetter(new ByMethodPropertyValueGetter(prop, getter));
            }, (prop, type, setter) -> {
                addProperty(prop);
                addSetter(new ByMethodPropertyValueSetter(prop, type, setter));
            });
        }
    }

    private static void processMethod(Method m, BiConsumer<String, Method> getterConsumer,
                                      TiConsumer<String, Class<?>, Method> setterConsumer) {
        if (m.getDeclaringClass() == Object.class) {
            return;
        }
        if (Modifier.isStatic(m.getModifiers())) {
            return;
        }
        Parameter[] parameters = m.getParameters();
        String name = m.getName();
        // 可能是 get 方法
        if (CollectionUtil.isEmpty(parameters)) {
            if (name.startsWith("is")) {
                char[] chars = name.toCharArray();
                chars[2] = Character.toLowerCase(chars[2]);
                getterConsumer.accept(new String(chars).substring(2), m);

            } else if (name.startsWith("get")) {
                char[] chars = name.toCharArray();
                chars[3] = Character.toLowerCase(chars[3]);
                getterConsumer.accept(new String(chars).substring(3), m);
            }
        }
        // 可能是 set 方法
        else if (parameters.length == 1) {
            if (name.startsWith("set")) {
                char[] chars = name.toCharArray();
                chars[3] = Character.toLowerCase(chars[3]);
                Class<?> paramType = parameters[0].getType();
                setterConsumer.accept(new String(chars).substring(3), paramType, m);
            }
        }
    }

    private interface TiConsumer<T1, T2, T3> {
        void accept(T1 t1, T2 t2, T3 t3);
    }

}
